﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace CostomGameServer
{
	static class UdpManager
	{
		static UdpClient client;
		static IPEndPoint local;
		static List<IPEndPoint> remotes = new List<IPEndPoint>( );
		static IPEndPoint remoteBuffer;
		static byte[ ] refuse;

		delegate byte[ ] ProtoBufferSerializerDelegate(DataPackage.Package o);
		delegate DataPackage.Package ProtoBufferDeserializerDelegate(byte[ ] o);
		static ProtoBufferSerializerDelegate pfs;
		static ProtoBufferDeserializerDelegate pfd;



		static bool isActive = false;

		static internal void Init() {
			local = new IPEndPoint( IPAddress.Any, Options.ServerListenPort );
			client = new UdpClient( local );

			refuse = ProtobufFormatter.Serialize( PackageManager.Refusal );

			pfs += ProtobufFormatter.Serialize;
			pfd += ProtobufFormatter.Deserialize<DataPackage.Package>;

			Console.WriteLine( $"UDP服务已开启，当前时间{DateTime.Now}" );
		}

		static internal async void Start() {
			isActive = true;
			await Loop( );
		}

		//数据的接受是与Tick并行的，不受Tick控制
		static internal Task Loop() {
			return new Task( () => {
				while (isActive) {
					Receive( );
				}
			} );
		}

		internal static void Stop() {
			isActive = false;
		}

		internal static async void Send(DataPackage.Package p) {
			await Task.Run( () => {
				byte[ ] buf = pfs( p );
				foreach (var q in remotes) {
					client.Send( buf, buf.Length, q );
				}
			} );
		}

		internal static async void SendPackageByTime(int timestamp, IPEndPoint ipep) {
			await Task.Run( () => {
				byte[ ] buf = pfs( PackageManager.GetPackageByTime( timestamp ) );
				client.Send( buf, buf.Length, ipep );
			} );
		}

		internal static void Receive() {
			try {
				byte[ ] msg = client.Receive( ref remoteBuffer );
				if (remotes.Count >= Options.ClientNums && !remotes.Contains( remoteBuffer )) {
					client.Send( refuse, refuse.Length, remoteBuffer );
				}
				else {
					PackageManager.Parse( ProtobufFormatter.Deserialize<DataPackage.Package>( msg ) );
				}
			}
			catch (Exception e) {
				Console.WriteLine( e );
			}
		}

	}
}
